package com.hinacom.pix.client;


import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.HapiContext;
import ca.uhn.hl7v2.model.DataTypeException;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.v25.message.QBP_Q21;
import ca.uhn.hl7v2.model.v25.message.QCN_J01;
import ca.uhn.hl7v2.model.v25.message.RSP_K21;
import ca.uhn.hl7v2.model.v25.message.RSP_K23;
import ca.uhn.hl7v2.model.v25.segment.MSH;
import ca.uhn.hl7v2.model.v25.segment.PID;
import ca.uhn.hl7v2.parser.Parser;
import com.hinacom.pix.entity.*;
import com.hinacom.pix.enums.ESex;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by fyu on 2016/9/1.
 */
public class PDQConsumer extends BaseClient {
    private static Logger logger = Logger.getLogger(PDQConsumer.class);
    private static String host;
    private static int port;
    private static String sendingApplicationName;
    private static String sendingFacilityName;
    private static String receivingApplicationName;
    private static String receivingFacilityName;
    private static final String QUERY_NAME = "IHE PDQ Query";

    static {

        ResourceBundle bundle = PropertyResourceBundle.getBundle("pix");
        host = bundle.getString("v2-pdq-host");
        String pixPort = bundle.getString("v2-pdq-port");
        port = Integer.parseInt(pixPort);
        sendingApplicationName = bundle.getString("sending-application-name");
        sendingFacilityName = bundle.getString("sending-facility-name");
        receivingApplicationName = bundle.getString("receiving-application-name");
        receivingFacilityName = bundle.getString("receiving-facility-name");
    }

    public List<Patient> query(PDQQueryParameter queryParameter) throws HL7Exception, ParseException {


        String result = this.queryToString(queryParameter);
        // convert Patient
        HapiContext context = new DefaultHapiContext();
        Parser p = context.getGenericParser();

        result = result.replace("\r\n","\r");
        result = result.replace("\n","\r");
        result = result.replace("\r","\r\n");

        logger.info("Query Response: " + result);



        List<Patient> patientList = null;
         /*
        Message message = p.parse(result);

        PID pid = null;
        if (message instanceof RSP_K23) {
            RSP_K23 response = (RSP_K23) message;
            pid = response.getQUERY_RESPONSE().getPID();
        }

        if (message instanceof RSP_K21) {
            RSP_K21 response = (RSP_K21) message;
            pid = response.getQUERY_RESPONSE().getPID();
        }

        patientList = this.convertResponseForK23(message, pid);
        */
        // fill patient
        return patientList;
    }

    private List<Patient> convertResponseForK23(Message rsp, PID pid) throws DataTypeException, ParseException {
        List<Patient> patientList = new ArrayList<Patient>();
        Patient patient = new Patient();
        PatientIdentifier internalIdentifier = new PatientIdentifier();
        patient.setInternalIdentifier(internalIdentifier);
        String id = pid.getPatientIdentifierList(0).getCx1_IDNumber().getValue();
        internalIdentifier.setId(id);
        String checkDigit = pid.getPatientIdentifierList(0).getCx2_CheckDigit().getValue();
        internalIdentifier.setCheckDigit(checkDigit);
        String schemeEmployed = pid.getPatientIdentifierList(0).getCx3_CheckDigitScheme().getValue();
        internalIdentifier.setSchemeEmployed(schemeEmployed);
        String identifierTypeCode = pid.getPatientIdentifierList(0).getCx5_IdentifierTypeCode().getValue();
        internalIdentifier.setIdentifierTypeCode(identifierTypeCode);
        String assigningFacility = pid.getPatientIdentifierList(0).getCx6_AssigningFacility().toString();
        // internalIdentifier.setAssigningFacility(assigningFacility);

        // convert assign authority
        AssigningAuthority assigningAuthority = new AssigningAuthority();
        internalIdentifier.setAssigningAuthority(assigningAuthority);
        String namespaceId = pid.getPatientIdentifierList(0).getAssigningAuthority().getNamespaceID().getValue();
        assigningAuthority.setNamespaceId(namespaceId);
        String universalId = pid.getPatientIdentifierList(0).getAssigningAuthority().getUniversalID().getValue();
        assigningAuthority.setUniversalId(universalId);
        String universalIdType = pid.getPatientIdentifierList(0).getAssigningAuthority().getUniversalIDType().getValue();
        assigningAuthority.setUniversalIDType(universalIdType);

        // patient name
        PatientName patientName = new PatientName();
        patient.setPatientName(patientName);
        patientName.setFirstName(pid.getPatientName(0).getFamilyName().toString());
        patientName.setLastName(pid.getPatientName(0).getGivenName().toString());
        patientName.setMiddleName(pid.getPatientName(0).getXpn3_SecondAndFurtherGivenNamesOrInitialsThereof().getValue());
        pid.getPatientName(0).getNameTypeCode().setValue(pid.getPatientName(0).getNameTypeCode().toString());

        // mother name
        PatientName motherName = new PatientName();
        if (pid.getMotherSMaidenName().length != 0) {
            motherName.setFirstName(pid.getMotherSMaidenName(0).getFamilyName().toString());
            motherName.setLastName(pid.getMotherSMaidenName(0).getGivenName().getValue());
            motherName.setMiddleName(pid.getMotherSMaidenName(0).getXpn3_SecondAndFurtherGivenNamesOrInitialsThereof().getValue());
        }

        if (pid.getDateTimeOfBirth().getTime().getValue() != null) {
            SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式
            String sBirth = pid.getDateTimeOfBirth().getTime().getValue();
            Date birthDay = df.parse(sBirth);
            patient.setBirthDay(birthDay);
        }

        if (pid.getPid8_AdministrativeSex().getValue() != null) {
            for (ESex sex : ESex.values()) {
                if (pid.getPid8_AdministrativeSex().getValue().equals(sex.getValue())) {
                    patient.setSex(sex);
                }
                break;
            }
        }

        if (pid.getRace().length != 0) {
            patient.setRace(pid.getRace(0).toString());
        }

        if (pid.getCountyCode().getValue() != null) {
            patient.setCounty(pid.getCountyCode().getValue());
        }

        if (pid.getPhoneNumberHome().length != 0) {
            patient.getHomePhoneNumber().setCountryCode(pid.getPhoneNumberHome(0).getXtn5_CountryCode().toString());
            patient.getHomePhoneNumber().setAreaCode(pid.getPhoneNumberHome(0).getXtn6_AreaCityCode().toString());
            patient.getHomePhoneNumber().setNumber(pid.getPhoneNumberHome(0).getXtn7_LocalNumber().toString());
            patient.getHomePhoneNumber().setExtension(pid.getPhoneNumberHome(0).getXtn8_Extension().toString());
            patient.getHomePhoneNumber().setNote(pid.getPhoneNumberHome(0).getXtn9_AnyText().toString());
            patient.getHomePhoneNumber().setType(PhoneType.HOME);
        }

        if (pid.getPhoneNumberBusiness().length != 0) {
            patient.getBusinessPhoneNumber().setCountryCode(pid.getPhoneNumberBusiness(0).getXtn5_CountryCode().toString());
            patient.getBusinessPhoneNumber().setAreaCode(pid.getPhoneNumberBusiness(0).getXtn6_AreaCityCode().toString());
            patient.getBusinessPhoneNumber().setNumber(pid.getPhoneNumberBusiness(0).getXtn7_LocalNumber().toString());
            patient.getBusinessPhoneNumber().setExtension(pid.getPhoneNumberBusiness(0).getXtn8_Extension().toString());
            patient.getBusinessPhoneNumber().setNote(pid.getPhoneNumberBusiness(0).getXtn9_AnyText().toString());
            patient.getBusinessPhoneNumber().setType(PhoneType.WORK);
        }

        if (pid.getSSNNumberPatient().getValue() != null) {
            patient.setSsn(pid.getSSNNumberPatient().getValue());
        }

        patientList.add(patient);
        return patientList;
    }

    public String queryToString(PDQQueryParameter queryParameter) throws HL7Exception, ParseException {
        QBP_Q21 qbp = new QBP_Q21();
        MSH msh = qbp.getMSH();
        this.getQueryMSH(msh);

        qbp.getQPD().getQpd1_MessageQueryName().getCe1_Identifier().setValue(QUERY_NAME);
        qbp.getQPD().getQpd2_QueryTag().setValue(queryParameter.getTag());

        String pidParameter = queryParameter.generateParameter();
        qbp.getQPD().getQpd3_UserParametersInsuccessivefields().parse(pidParameter);

        qbp.getRCP().getRcp1_QueryPriority().setValue(queryParameter.getPriority());
        String returnRecordCount = String.valueOf(queryParameter.getReturnRecordCount());
        qbp.getRCP().getRcp2_QuantityLimitedRequest().getCq1_Quantity().setValue(returnRecordCount);
        qbp.getRCP().getRcp2_QuantityLimitedRequest().getCq2_Units().parse(queryParameter.getReturnUnits());

        if(StringUtils.isNotEmpty(queryParameter.getContinuationPointer()))
        {
            qbp.getDSC().getDsc1_ContinuationPointer().setValue(queryParameter.getContinuationPointer());
            // DSC-2 (Continuation Style) shall always contain I, signifying that this is part of an interactive continuation message.
            qbp.getDSC().getDsc2_ContinuationStyle().setValue("I");
        }

        String sMessage = qbp.toString().replace("\r", "\r\n");
        sMessage = sMessage.toString().replace(PDQQueryParameter.PID_PARAMETER_SPLIT, PDQQueryParameter.PID_PARAMETER_SPLIT_ORIGINAL);

        logger.info("Query Request: " + sMessage);

        String result = this.sendMessage(sMessage);
        return result;
    }

    private void getQueryMSH(MSH msh) throws HL7Exception {
        // QBP^Q22^QBP_Q21
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式
        String now = df.format(new Date());
        msh.getMsh1_FieldSeparator().setValue("|");
        msh.getMsh2_EncodingCharacters().setValue("^~\\&");
        msh.getSendingApplication().getNamespaceID().setValue(sendingApplicationName);
        msh.getSendingFacility().getHd1_NamespaceID().setValue(sendingFacilityName);
        msh.getReceivingApplication().getNamespaceID().setValue(receivingApplicationName);
        msh.getReceivingFacility().getHd1_NamespaceID().setValue(receivingFacilityName);

        // generate a random id
        String controlId = UUID.randomUUID().toString().substring(0, 8);
        controlId = String.valueOf(Long.parseLong(controlId, 16));

        msh.getMessageControlID().setValue(String.format("HINA-%s", controlId));
        msh.getDateTimeOfMessage().getTime().setValue(now);
        msh.getMessageType().getMsg1_MessageCode().setValue("QBP");
        msh.getMessageType().getMsg2_TriggerEvent().setValue("Q22");
        msh.getMessageType().getMsg3_MessageStructure().setValue("QBP_Q21");

        msh.getMsh11_ProcessingID().getPt1_ProcessingID().setValue("P");
        msh.getMsh12_VersionID().getVersionID().setValue("2.5");
    }

    public void cancelQuery(PDQQueryParameter queryParameter) throws HL7Exception, ParseException {
        String messageString = cancelQueryToString(queryParameter);
        messageString = "";
    }

    public String cancelQueryToString(PDQQueryParameter queryParameter) throws HL7Exception, ParseException {
        QCN_J01 qbp = new QCN_J01();
        MSH msh = qbp.getMSH();
        this.getCancelQueryMSH(msh);

        String messageString = qbp.toString().replace("\r", "\r\n");
        messageString = messageString.toString().replace(PDQQueryParameter.PID_PARAMETER_SPLIT, PDQQueryParameter.PID_PARAMETER_SPLIT_ORIGINAL);

        logger.info("Cancel query request: " + messageString);
        String result = this.sendMessage(messageString);
        return result;
    }

    private void getCancelQueryMSH(MSH msh) throws HL7Exception {
        // QCN^J01^QCN_J01
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式
        String now = df.format(new Date());
        msh.getMsh1_FieldSeparator().setValue("|");
        msh.getMsh2_EncodingCharacters().setValue("^~\\&");
        msh.getSendingApplication().getNamespaceID().setValue(sendingApplicationName);
        msh.getSendingFacility().getHd1_NamespaceID().setValue(sendingFacilityName);
        msh.getReceivingApplication().getNamespaceID().setValue(receivingApplicationName);
        msh.getReceivingFacility().getHd1_NamespaceID().setValue(receivingFacilityName);

        // generate a random id
        String controlId = UUID.randomUUID().toString().substring(0, 8);
        controlId = String.valueOf(Long.parseLong(controlId, 16));

        msh.getMessageControlID().setValue(String.format("HINA-%s", controlId));
        msh.getDateTimeOfMessage().getTime().setValue(now);
        msh.getMessageType().getMsg1_MessageCode().setValue("QCN");
        msh.getMessageType().getMsg2_TriggerEvent().setValue("J01");
        msh.getMessageType().getMsg3_MessageStructure().setValue("QCN_J01");

        msh.getMsh11_ProcessingID().getPt1_ProcessingID().setValue("P");
        msh.getMsh12_VersionID().getVersionID().setValue("2.5");
    }

    @Override
    protected String getHost() {
        return host;
    }

    @Override
    protected int getPort() {
        return port;
    }
}
